import EventEmitter from "events";
import { Kline, Indicator, Quant, Signal } from "../lib/quant";
import { Slope } from "../lib/quant/indicator/slope";
import { MA } from "../lib/quant/indicator/ma";
import { Statistics } from "./indicators/statistics";
import {  MergeData } from "./DataHandler";
import { strategyPiepline } from "./StrategyPiepline";

import { Vector } from "./indicators/vector";

export interface CustomIndicators {
  slope_15m: number;
  slope_4h: number;
  slope_1d: number;

  change_rate_15m: number;
  close_ma_rate_15m: number;
  close_ma_rate_4h: number;
  close_ma_rate_1d: number;
  volume_rate_15m: number;
  volume_rate_4h: number;
  volume_rate_1d: number;

  exceptional_undulation_rate_15m: number;
  exceptional_undulation_rate_4h: number;
  exceptional_undulation_rate_1d: number;
  // 下面是不用的
  point_peaks_15m?: number;
  point_valleys_15m?: number;
 

  sell_rate_15m?: number;
  sell_rate_4h?: number;
  sell_rate_1d?: number;

  predict_buy_15m?: number;
  predict_sell_15m?: number;

  vector_4h?: number[];
  vector_1d?: number[];

  vector_stort_15m?: number[];
  vector_stort_4h?: number[];
  vector_stort_1d?: number[];
  
  statistics_4h_max?: number;
  statistics_4h_min?: number;
  statistics_1d_max?: number;
  statistics_1d_min?: number;
}


export const periodDis = {
  '15m': 30 * 16,
  '4h': 30 * 6,
  '1d': 30,
}

export class MixIndicator {
  quantMap = {
    '15m': new Quant<Kline & {action?: Signal, label?: number}>(),
    '4h': new Quant(),
    '1d': new Quant(),
  }
  private eventEmitter = new EventEmitter();
  isMock = false;
  constructor({isMock}: {isMock: boolean}) {
    this.isMock = isMock;
    this.init();
  }

  init() {
    this.addIndicator('15m');
    this.addIndicator('4h');
    this.addIndicator('1d');
    const quant_15m = this.quantMap['15m'];

    quant_15m.addStrategy('mix-indicator', (indicators, bar) => {
      const feature_vector_detail = this.getFeatureVectorDetail(bar);
      if (feature_vector_detail == null) {
        return
      }
      this.eventEmitter.emit('mix-indicator', bar, indicators, feature_vector_detail);
      return undefined
    });
  }
  addIndicator(period: keyof MixIndicator['quantMap']) {

    switch(period) {

      case '15m':
        this.quantMap[period].addIndicator('ma240', new MA({ period: 240, key: 'close' }));
        this.quantMap[period].addIndicator('slope', new Slope({ key: 'close', period: 15, slopeTolerant: 0.4 }));
        this.quantMap[period].addIndicator('vector_stort', new Vector({ period: 30 }));
        this.quantMap[period].addIndicator('statistics', new Statistics({ period: 240, amplitude_threshold: 0.009 }));
        break;
      case '4h':
        this.quantMap[period].addIndicator('ma120', new MA({ period: 120, key: 'close' }));
        this.quantMap[period].addIndicator('slope', new Slope({ key: 'close', period: 9, slopeTolerant: 0.3 }));
        if (this.isMock) {
          this.quantMap[period].addIndicator('vector', new Vector({ period: 90 }));
        }
        this.quantMap[period].addIndicator('vector_stort', new Vector({ period: 30 }));
        this.quantMap[period].addIndicator('statistics', new Statistics({ period: 120, amplitude_threshold: 0.023, positionCount: 5, slope_threshold: 0.01 }));
        break;
      case '1d':
        this.quantMap[period].addIndicator('ma60', new MA({ period: 60, key: 'close' }));
        this.quantMap[period].addIndicator('slope', new Slope({ key: 'close', period: 5, slopeTolerant: 0.2 }));
        if (this.isMock) {
          this.quantMap[period].addIndicator('vector', new Vector({ period: 30 }));
        }
        this.quantMap[period].addIndicator('vector_stort', new Vector({ period: 16 }));
        this.quantMap[period].addIndicator('statistics', new Statistics({ period: 60, amplitude_threshold: 0.05, positionCount: 4, slope_threshold: 0.04 }));
    }
  }
  getFeatureVectorDetail(bar: Kline) {
    const quant_15m = this.quantMap['15m'];
    const quant_4h = this.quantMap['4h'];
    const quant_1d = this.quantMap['1d'];
    const indicators_15m = quant_15m.getIndicators();
    const indicators_4h = quant_4h.getIndicators();
    const indicators_1d = quant_1d.getIndicators();


    const slope_15m = (indicators_15m.get('slope') as Slope);
    const slope_4h = (indicators_4h.get('slope') as Slope);
    const slope_1d = (indicators_1d.get('slope') as Slope);


    const statistics_15m = (indicators_15m.get('statistics') as Statistics).getValue();
    const statistics_4h = (indicators_4h.get('statistics') as Statistics).getValue();
    const statistics_1d = (indicators_1d.get('statistics') as Statistics).getValue();
    const vector_stort_15m = (indicators_15m.get('vector_stort') as Vector).getValue();
    const vector_stort_4h = (indicators_4h.get('vector_stort') as Vector).getValue();
    const vector_stort_1d = (indicators_1d.get('vector_stort') as Vector).getValue();
    const vector_4h = indicators_4h.get('vector') ? (indicators_4h.get('vector') as Vector).getValue() : undefined;
    const vector_1d = indicators_1d.get('vector') ? (indicators_1d.get('vector') as Vector).getValue() : undefined;


    const result_15m = strategyPiepline.run({
      quant: quant_15m,
      indicators: indicators_15m,
      bar
    });
    const result_4h = strategyPiepline.run({
      quant: quant_4h,
      indicators: indicators_4h,
      bar
    });
    const result_1d = strategyPiepline.run({
      quant: quant_1d,
      indicators: indicators_1d,
      bar
    });

    // 需要改 jsonToVectors\ vectorsToJson
    const feature_vector_detail: CustomIndicators = {
      // 状态
      slope_15m: slope_15m.getValue(),
      slope_4h: slope_4h.getValue(),
      slope_1d: slope_1d.getValue(),
      // 比率
      change_rate_15m: result_15m.customIndicators.change_rate,
      close_ma_rate_15m: result_15m.customIndicators.close_ma_rate,
      close_ma_rate_4h: result_4h.customIndicators.close_ma_rate,
      close_ma_rate_1d: result_1d.customIndicators.close_ma_rate,
      volume_rate_15m: result_15m.customIndicators.volume_rate,
      volume_rate_4h: result_4h.customIndicators.volume_rate,
      volume_rate_1d: result_1d.customIndicators.volume_rate,

      exceptional_undulation_rate_15m: statistics_15m ? statistics_15m.exceptional_undulation_rate : 0,
      exceptional_undulation_rate_4h: statistics_4h ? statistics_4h.exceptional_undulation_rate : 0,
      exceptional_undulation_rate_1d: statistics_1d ? statistics_1d.exceptional_undulation_rate : 0,
      // 其他
   

      point_peaks_15m: statistics_15m ? statistics_15m.point_peaks : 0,
      point_valleys_15m: statistics_15m ? statistics_15m.point_valleys : 0,

      sell_rate_15m: result_15m.customIndicators.sell_rate,
      sell_rate_4h: result_4h.customIndicators.sell_rate,
      sell_rate_1d: result_1d.customIndicators.sell_rate,

      vector_4h: vector_4h? vector_4h.vector : [],
      vector_1d: vector_1d ? vector_1d.vector : [],
      vector_stort_15m: vector_stort_15m ? vector_stort_15m.vector : [],
      vector_stort_4h: vector_stort_4h ? vector_stort_4h.vector : [],
      vector_stort_1d: vector_stort_1d ? vector_stort_1d.vector : [],
      statistics_4h_max: statistics_4h ? statistics_4h.max : 0,
      statistics_4h_min: statistics_4h ? statistics_4h.min : 0,
      statistics_1d_max: statistics_1d ? statistics_1d.max : 0,
      statistics_1d_min: statistics_1d ? statistics_4h.min : 0,
    }
    if (quant_15m.currentData == null || quant_4h.currentData == null || quant_1d.currentData == null) {
      return feature_vector_detail;
    }
    // console.log(Object.keys(feature_vector_detail).length - 2)
    return feature_vector_detail;
  }

  onMixIndicator(callback: (bar: MergeData, indicators: Map<string, Indicator<Kline>>, feature_vector_detail: CustomIndicators) => void) {
    this.eventEmitter.on('mix-indicator', callback);
  }
  push(data: MergeData, period: keyof MixIndicator['quantMap']) {
    if (data.close === undefined || data.open == undefined) {
      console.error('MixIndicator.push 数据有误', data)
      return;
    }
    if (this.quantMap[period]) {
      this.quantMap[period].addData(data);
    }
  }
  update(data: MergeData, period: keyof MixIndicator['quantMap']) {
    if (data.close === undefined || data.open == undefined) {
      console.error('update 数据有误', data)
      return;
    }
    if (this.quantMap[period]) { 
      this.quantMap[period].updateLastData(data);
    }
  }
  destroy() {
    this.eventEmitter.removeAllListeners();
    this.quantMap['15m'].destroy();
    this.quantMap['4h'].destroy();
    this.quantMap['1d'].destroy();
  }
}
